#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "Task.hpp"
using namespace std;

#define PROCESS_NUM 5

/*
typedef struct slot //插槽
{
    pid_t subid;
    int fd;
}slot;
*/
typedef pair<pid_t, int> slot;

// 父进程随机生成一个命令编号 通过father_pipefd[1]写到管道
// 子进程调用通过child_pipefd[0]获取父进程传输的命令编号存入command_ref并返回
// 若command_ref合法 则执行相关操作

// 父进程把命令编号通过father_pipefd[1]写到管道
void sendCommand(int fatherWriter, uint32_t command_ref)
{
    // ssize_t write(int __fd, const void *__buf, size_t __n)
    write(fatherWriter, &command_ref, sizeof(command_ref));
}

// 子进程通过child_pipefd[0]获取父进程传输的命令编号存入command_ref并返回
int getCommand(int childReader, bool &quit)
{
    uint32_t command_ref = 0; // u：无符号 32：32bit ==> 无符号4byte

    // ssize_t read(int __fd, void *__buf, size_t __nbytes)
    ssize_t s = read(childReader, &command_ref, sizeof(command_ref));
    if (s == 0)
    {
        quit = true;
        return -1;
    }
    assert(s == sizeof(uint32_t));

    return command_ref;
}

int main()
{
    Load();

    vector<pair<pid_t, int>> slots; // 新创建的child_pid : fatherWriter

    // 创建PROCESS_NUM个进程
    for (int i = 0; i < PROCESS_NUM; i++)
    {
        // 每创建一个新子进程 执行如下操作
        // fork一直是father执行的 fork之后的每一个child都掉入while中直到满足某条件使该子进程退出
        // 每创建一个新子进程 把该子进程pid 和 父进程写端 存入slots

        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;

        pid_t id = fork();
        assert(id != -1);

        // child -- 读 关闭写端
        if (id == 0)
        {
            close(pipefd[1]);

            while (true)
            {
                // 阻塞等待获取命令
                bool quit = false;
                int command_ref = getCommand(pipefd[0], quit);
                if (quit == true)
                    break;

                // 执行对应的命令
                if (command_ref >= 0 && command_ref < cmdSetsize())
                {
                    cmdSet[command_ref]();
                }
                else
                {
                    cout << "非法command: " << command_ref << endl;
                }
            }

            exit(1);
        }

        // father -- 写 关闭读端
        close(pipefd[0]);
        slots.push_back(pair<pid_t, int>(id, pipefd[1]));
    }

    // 父进程派发任务
    // void srand(unsigned int __seed)  时间戳^父进程^乱码 ==> 让数据源/初始值更随机
    //异或操作：位运算，速度快
    srand((unsigned long)time(nullptr) ^ getpid() ^ 23323123123L); 
    while (true)
    {
        // int rand(); rand会先调用srand 将其返回值作为初始值
        int command_ref = rand() % cmdSetsize(); // 随机生成命令编号 -- 调用哪一个命令

        // 随机选择进程来完成任务 ==> 随机数方式的负载均衡
        int child_ref = rand() % slots.size(); // 随机生成子进程编号 -- 调用哪一个子进程

        // void sendCommand(pid_t execChild, int fatherWriter, uint32_t command_ref)
        sendCommand(slots[child_ref].second, command_ref);

        cout << "father[" << getpid() << "] call child[" << slots[child_ref].first
             << "] execute " << cmdContent[command_ref]
             << " through fatherWriter " << slots[child_ref].second << endl;

        sleep(1);

        // while循环未设置结束操作 下面的for无法执行
        // 致使fd写端未完全关闭(测试程序 ctrl+C结束该主进程 对应fd全部自动关闭)
    }

    // close father对每一个管道的pipefd[1] 之后每一个child_read读到文件尾-->退出
    for (const auto &slot : slots)
    {
        close(slot.second);
    }

    // 阻塞等待创建的每一个child 获取退出状态 回收信息
    for (const auto &slot : slots)
    {
        waitpid(slot.first, nullptr, 0);
    }
}